Skip to content

Hydration

When we use server-side rendering, the browser receives a fully-formed page. Ideally, all of the necessary HTML and CSS should be included.

But a huge component of React applications is interactivity. React is all about building dynamic, stateful applications. Most of our time in this course has been spent learning about how to make our applications interactive, with state and effects.

The process of turning the initial static HTML file into an interactive web application is called hydration.

I really like the way React core team member Dan Abramov explains it:

Hydration is like watering the “dry” HTML with the “water” of interactivity and event handlers.

At a high level, the process of hydration goes something like this:

  • Perform a “speed render”, to figure out the shape of our component tree, and to initialize our component instances.
  • Wire up all of the interactivity (add event listeners, attach refs, etc).

In a client-side rendering environment, the initial render is responsible for creating all of the DOM nodes. With server-side rendering, however, all of those DOM nodes already exist. Instead, React has to “adopt” the DOM.

Here's how I picture this working:

Static
Interactive
React Logo

The grey boxes represent static DOM nodes, embedded in the server-generated HTML. On the client, React quickly constructs the component tree and matches it to the DOM, so that it can wire up event listeners and make the application interactive.

Updating our graphs

Here's what our updated “SSR” graph looks like, now that we know about hydration:

This is a data visualization which shows a sequence of events between client and server. Each event is represented here as a list item.

  1. "Render application" on server. Duration: 8 units of time.
  2. Request to server. Duration: 3 units of time.
  3. "Download JavaScript" on client. Duration: 12 units of time.
  4. "Hydrate" on client. Duration: 4 units of time.

Our “Load JavaScript” step has been broken into two phases: Downloading the JS bundle, and hydrating the React application.

Hydration in code

This requires a slightly different approach. Here's how we'd change the index.js file at the root of our React application:

import React from 'react';
-import { createRoot } from 'react-dom/client';
+import { hydrateRoot } from 'react-dom/client';
function App() {
return (
<h1>Hello world!</h1>
);
}
-const root = createRoot(document.querySelector('#root'));
-root.render(<App />);
+hydrateRoot(document.querySelector('#root'), <App />);

The hydrateRoot method is how we adopt an existing DOM structure.

Now, to be clear, we don't generally write this code ourselves. Often, server-side rendering is a feature of React meta-frameworks like Next.js, and they handle this stuff internally.

I think it's important to understand how this stuff works conceptually though. There are a couple of “gotchas” with hydration, and server-side rendering in general. We'll explore them a little later in this module.